#include "SymtableV0.h"
#include "Test.h"
#include "Helper.h"
#include <assert.h>

#ifdef WIN
	//#include "stdafx.h"
#endif 
//WIN

const size_t SymtableV0::HASH_CNT = 28;

SymtabEntry::SymtabEntry(Information info) :
    info(info)
{}

SymtabEntry::~SymtabEntry(){}

void SymtabEntry::setPrev(SymtabEntry* prev)
{
    this->prev = prev;
}

Information SymtabEntry::getInfo()
{
    return info;
}

void SymtabEntry::setInfo(Information info)
{
    this->info = info;
}

//public methods:
SymtableV0::SymtableV0() :
    tab(new StringTabV0()),
    map(new SymtabEntry*[HASH_CNT]),
    entriesPerHash(new int[HASH_CNT]),
    lastChar('\0')
{
    assert(sizeof(Key) > sizeof(Hash));//hashes are part of keys

    memset(map, NULL, HASH_CNT * sizeof(SymtabEntry*));//set all pointers to NULL
    
    for(size_t i = 0; i < HASH_CNT; ++i)
    {
        entriesPerHash[i] = 0;
    }
}

SymtableV0::~SymtableV0()
{
    delete tab;
    delete[] map;
    delete[] entriesPerHash;
}

Hash SymtableV0::calculateHash(Lexem lexem)
{
    if(lexem.getLength() < 17)
    {
        return  lexem.getChars()[ 0]  % HASH_CNT;
    } else {
        return (lexem.getChars()[16]  +
                lexem.getChars()[ 8]  +
                lexem.getChars()[ 0]) % HASH_CNT;
    }
}

void SymtableV0::putChar(char c)
{
    tab->putChar(c);
}

Key SymtableV0::mkToken(TType type)
{
    assert(type == TOK_IDENT);
    Lexem lexem = tab->mkLexem();
    Hash hash = calculateHash(lexem);

    //CLGR make lookup(...) here

    
    SymtabEntry* entryFirst = map[hash];
    SymtabEntry* entryNew   = new SymtabEntry(Information(lexem.getChars(), type));//CLGR IMPROVE
    if(entryFirst != NULL)//if a first entry exists
        entryNew->setPrev(entryFirst);//make first to second entry
    map[hash] = entryNew;

    
    Key key = entriesPerHash[hash] << sizeof(int);//set the upper-part of the {int,int}-variable to the number of entries (values) with the same hash-value
    key    |= hash;                               //set the lower-part of the {int,int}-variable to hash
    entriesPerHash[hash]++;

    return key;
}

//CLGR TODO There are multiple entries with the same key. Dont know how to find the correct one. Returning first. 
Information SymtableV0::lookup(Key key)
{
    return map[key][0].getInfo();
    
    /*for(size_t i = 0; map[key][i] != NULL; ++i)
    {
        map[key][i].getInfo();
    }
    


	return Information(NULL, NO_TYPE);*/
}

int SymtableV0::unputCharsAndGetAsInt()
{
    return tab->unputCharsAndGetAsInt();
}

char SymtableV0::unputAndGetChar()
{
    return tab->unputAndGetChar();
}

/*
int main()
{
    Test::test();
	return 0;
}
*/